package com.lzyyj.common;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/** 
 * 泛型相关的实用工具类. 
 * @author lzyyj 
 */ 
public class GenericsUtils {
	
    private static final Log log = LogFactory.getLog(GenericsUtils.class); 

    /** 
     * 通过反射,获得定义 Class 时在声明父类时指定的范型参数的类型. 如 public BookManager extends GenricManager<Book>
     * 为避免歧义，还在推荐明确指明超类及泛型序号 
     * @param clazz 要检查的类 
     * @return the first generic declaration, or <code>Object.class</code> if cannot be determined 
     */ 
    @Deprecated
    public static Class<?> getSuperClassGenricType(Class<?> clazz) {
        return getSuperClassGenricType(clazz, clazz.getSuperclass(), 0); 
    } 

    /** 
     * 从指定子类到目标超类的继承链中查找对目标超类指定泛型定义所实际声明的类型. 
     * 如超类 public class BaseService<T, PK extends Serializable> implements IBaseService<T, PK>,Serializable 
     *   子类 public class MemberService<PK extends Serializable, T> extends UserService<Member, PK>
     *   注意，两个类定义中的 T 没有直接关系的哟 
     * @param clazz 要检查的类 
     * @param tarSuperClass 目标超类 
     * @param index 目标超类中的泛型参数序号，从0算起 
     * @return the index generic declaration, or <code>Object.class</code> if cannot be determined 
     */ 
    public static Class<?> getSuperClassGenricType(Class<?> subClass, Class<?> tarSuperClass, String genParamName) {
    	Class<?> result = null;

    	if (genParamName!=null&&genParamName.length()>0&&tarSuperClass!=null){
    		int index =  getGenParamIndex(tarSuperClass, genParamName);
    		if (index>=0){
    			result = getSuperClassGenricType(subClass, tarSuperClass, index);
    		}
    	}
    	return result;
    }

    /** 
    /** 
     * 从指定子类到目标超类的继承链中查找对目标超类指定泛型定义所实际声明的类型. 
     * 如超类 public class BaseService<T, PK extends Serializable> implements IBaseService<T, PK>,Serializable 
     *   子类 public class MemberService<PK extends Serializable, T> extends UserService<Member, PK>
     *   注意，两个类定义中的 T 没有直接关系的哟 
     * @param clazz 要检查的类 
     * @param tarSuperClass 目标超类 
     * @param index 目标超类中的泛型参数序号，从0算起 
     * @return the index generic declaration, or <code>Object.class</code> if cannot be determined 
     */ 
    public static Class<?> getSuperClassGenricType(Class<?> subClass, Class<?> tarSuperClass, int index) {
    	Class<?> result = null;

    	if (subClass!=null&&subClass!=Object.class&&tarSuperClass!=Object.class){
			// 创建子类继承链表
			Map<Class<?>, Class<?>> subClassMap = createSubClassMap(subClass, tarSuperClass);

			// 
			Class<?> clazz;
			Class<?> superClass;
			superClass = tarSuperClass;
			while (subClassMap.containsKey(superClass)&&result==null){
				clazz = subClassMap.get(superClass);

				if (superClass.getSimpleName().equals("MemberService")){
					log.debug("MemberService：");
				}
				
				Type genType = clazz.getGenericSuperclass();
			    if (genType instanceof ParameterizedType){
			    	Type[] params = ((ParameterizedType)genType).getActualTypeArguments(); 

			    	// 是目标类
			        if (index < 0 || index >= params.length ) { 
			            log.error(" 要查询的泛型参数序号不在有效范围内 Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length); 
			        }else{
			    		Type type = params[index];
			        	if (type instanceof Class){
			        		result = (Class<?>)type; 
			        	}else if(type instanceof ParameterizedType){
			        		result = (Class<?>)((ParameterizedType)type).getRawType();
			        	}else if (type instanceof TypeVariable){
			        		String name = ""+type;
			        		// 解析该名称在泛型定义时的序号
			        		// 还有子类吗
			        		if (subClassMap.containsKey(clazz)){
			        			// 还有子类，继续推导
				        		index =getGenParamIndex(clazz, name);
			        		}
			        	}else{
			        		log.debug("指定的泛型参数仍然还是一个泛型，不是实际类型："+type);
			        	}
			        }
			    }
			    superClass = clazz;
			}
    	}
        
        return result;
    }

	/**
	 * 返回指定类型中指定泛型参数的位置序号，从0算起
	 * @param clazz
	 * @param genParamName
	 * @return 泛型参数位置序号
	 */
	public static int getGenParamIndex(Class<?> clazz, String genParamName) {
		int index =-1;
		if (genParamName!=null&&genParamName.length()>0&&clazz!=null){
			TypeVariable<?>[] typeVariableList = clazz.getTypeParameters();
			for(int i=0;i<typeVariableList.length;i++){
				TypeVariable<?>  typeVar = typeVariableList[i];
				if (typeVar.getName().equals(genParamName)){
					index = i;
					break;
				}
			}
		}
		return index;
	}

	/**
	 * 返回指定类型的指定方法签名的方法
	 * @param clazz
	 * @param methodName
	 * @param paramClasses
	 * @return
	 */
	public static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramClasses) {
		Method method;
		try {
			method = clazz.getDeclaredMethod(methodName, paramClasses);
		} catch (Exception e) {
			method = null;
		}
		return method;
	}

	private static Map<Class<?>, Class<?>> createSubClassMap(Class<?> subClass, Class<?> targetClass) {
		Map<Class<?>,Class<?>> subClassMap = new HashMap<Class<?>, Class<?>>();

		// 构建继承链表
		Class<?> clazz = subClass;
		Class<?> superClass;
		while (clazz!=null&&clazz!=Object.class){
			superClass = clazz.getSuperclass();
			
			subClassMap.put(superClass, clazz);
		    if (superClass==targetClass){
		    	break;
		    }
			
			clazz = superClass;
		}
		
		return subClassMap;
	}
	
}
